/**
* Name: Ex L6b1 - verification dashboard final
* Author: WALLENTIN, Gudrun
* Description: Exercise of the UNIGIS Salzburg optional module
* GAMA dashboard to assist semantic code verification
*/

model ExL6b1_verificationdashboardfinal


global torus: true {

	// --- structural parameters ------------------------------------------
	int grid_size <- 4;
	int nb_sheep <- 3;

	// --- initial state ---------------------------------------------------
	int initial_grass <- 20;
	int initial_energy <- 20;

	// --- process rates ---------------------------------------------------
	int regrowth_per_step <- 1;   // per cell, per step
	int grass_per_meal <- 5;      // grass removed and converted to energy
	int metabolic_cost <- 2;      // energy burnt per sheep, per step
	int max_grass <- 30;      // standing biomass ceiling per cell

	//OBSERVATION widget: real spatial dimension
	geometry shape <- square (1 #km);

	//OBSERVATION widget: real temporal dimension
	float step <- 1 #day;
	date start_date <- #now;

	init {
		create sheep number: nb_sheep; 		
	}
	
	//OBSERVATION widget: report individual sheep state
	reflex report when: every(10 #day) {
	    ask first(sheep) {
	        write "" + (start_date + step*cycle) + "  " + name + "  energy " + energy + "  on " + my_pasture;
	    }
	}	
}

species sheep skills:[moving]{

	// The sheep holds a reference to the cell it occupies.
	pasture my_pasture;
	int energy <- initial_energy;
	//OBSERVATION widget: added units to speed
	float my_speed <- 100.0 #m / #day;      // drift off depleted grass onto fresh grass

	init {
		my_pasture <- one_of(pasture intersecting self);
	}
	
	//BUG FIX: swapped order movement <-> eat
	reflex movement {
		do wander speed:my_speed;
		//BUG FIX: update "my_pasture"
		my_pasture <- one_of(pasture intersecting self);
	}
	
	//eat: remove grass and gain energy
	reflex eat {
		if (my_pasture.grass >= grass_per_meal) {
			my_pasture.grass <- my_pasture.grass - grass_per_meal;
			energy <- energy + grass_per_meal;
		}
	}

	reflex metabolism {
		energy <- energy - metabolic_cost;
	}

	aspect default {
		//OBSERVATION widget: size depends on energy level
		draw circle(min([40, 1 + energy / 10])) color: #black;
		//OBSERVATION widget: energy labels
		draw string(energy) at: location + {20, 0} color: #black font: font("Helvetica", 10, #plain);
	}
}

// the pasture
grid pasture width: grid_size height: grid_size  {

	int grass <- initial_grass;
	
	//grass regrows linearly up to a max_grass limit
	reflex regrow {
	    grass <- min([grass + regrowth_per_step, max_grass]);
	    
	    //OBSERVATION widget: colour depends on grass, normalised to max_grass 
		int g <- int(255 * grass / max_grass);
		color <- rgb(255 - g, 255, 255 - g);        // white when empty, green when full   
	}
}

experiment grazing type: gui {

	// dashboard
	output {
		display grazing_view type: 2d {
			grid pasture border: #lightgray;
			species sheep aspect: default;

		//OBSERVATION widget: clock
		overlay position: {5 #px, 5 #px} size: {220 #px, 40 #px}
           	background: #black transparency: 0.4 {
       			draw string(start_date + step*cycle, "dd MMM yyyy") at: {12 #px, 26 #px}
           		color: #white font: font("Helvetica", 14, #bold);
           	}	
		}
		
		//OBSERVATION widget: table with selected sheep attributes
		browse sheep attributes: ["name", "energy", "my_pasture"];
		
		//OBSERVATION widget: time-series charts
		display trends type: 2d {
			chart "stocks over time" type: series x_label: "day" y_label: "units" {
				data "total grass"  value: sum(pasture collect each.grass) color: #green marker: false;
				data "total energy" value: sum(sheep collect each.energy) color: #red marker: false;
			}
		}
		
		//OBSERVATION widget: energy distribution histogram
		display population type: 2d {
    		chart "energy per sheep" type: histogram {
        		datalist legend: sheep collect each.name value: sheep collect each.energy;
    		}
		}		

		//OBSERVATION widget: monitors with aggreagate system states
		monitor "total grass"        value: sum(pasture collect each.grass);		
		monitor "total energy"       value: sum(sheep collect each.energy);		
		monitor "mean energy"        value: mean(sheep collect each.energy);		
		monitor "poorest sheep"      value: min(sheep collect each.energy);
		monitor "cells at ceiling"   value: pasture count (each.grass = max_grass);
		monitor "cells below a meal" value: pasture count (each.grass < grass_per_meal);		
	}
}